package com.abel.bigwater.data.sanchuan

import com.abel.bigwater.data.BcdString
import com.abel.bigwater.data.Bit32Array
import com.abel.bigwater.data.UnknownPacketException
import io.netty.buffer.ByteBuf
import kotlin.experimental.and

class DayBillDataPart(_dataLen: Int?) : SanchuanData(_dataLen) {

    /**
     * 1 日结数据组数 本次将要发送多少组日结数据，范围 0-31。
     */
    var count: Short? = null

    /**
     * 1 日结数据指示 BIT0~1 日结累计流量格式
     * 0 格式 0 格式见参数表，参数编码 1110
    1 格式 1 累计流量 3 字节，单位 0.1 立方米。 16 进制低字节在前
    2 保留
    3 保留
    BIT2~3 日结数据内容
    0 内容 0 日结累计流量
    1 内容 1 日结累计正流+日结累计逆流
    2 保留
    3 保留
    BIT4~7 保留
     */
    var flag: DayBillFlagType? = null

    /**
     * 5*M
    日结累计流量 1
    5*M 是格式 0、数据 0 的情况，其他情况长度会不一样。目前最长为 10*M
    。。。 日结流量 M 为前一天的日结累计流量，依次往前推算至累计流量 1。
    日结累计流量 M
     */
    var forwardStrList: ArrayList<BcdString>? = null

    var reverseStrList: ArrayList<BcdString>? = null

    /**
     * 日结数据组
     */
    var forwardBillList: ArrayList<Double>? = null
        get() {
            field = if (forwardStrList == null) null
            else ArrayList<Double>().apply {
                forwardStrList.orEmpty().forEach {
                    add(
                            if (flag?.dayBillFormat == 0) it.toUlongLEHex()!! * 0.1 * 0.001
                            else it.toUlongLEHex(3)!! * 0.1
                    )
                }
            }

            return field
        }

    /**
     * 逆累计流量日结数据组
     */
    var revserseBillList: ArrayList<Double>? = null
        get() {
            field = if (reverseStrList == null) null
            else ArrayList<Double>().apply {
                reverseStrList.orEmpty().forEach {
                    add(
                            if (flag?.dayBillFormat == 0) it.toUlongLEHex()!! * 0.1 * 0.001
                            else it.toUlongLEHex(3)!! * 0.1
                    )
                }
            }

            return field
        }

    /**
     * 计算数据长度，针对解析和打包
     */
    override fun computeDataLen(): Int {
        dataLen = when {
            flag?.dayBillFormat == 0 && flag?.dayBillContent == 0 -> 1 + 1 + 5 * count!!
            flag?.dayBillFormat == 0 && flag?.dayBillContent == 1 -> 1 + 1 + (5 + 5) * count!!
            flag?.dayBillFormat == 1 && flag?.dayBillContent == 0 -> 1 + 1 + 3 * count!!
            flag?.dayBillFormat == 1 && flag?.dayBillContent == 1 -> 1 + 1 + (3 + 3) * count!!
            else -> {
                throw UnknownPacketException("保留格式: ${flag?.back?.toString(16)}H")
            }
        }

        return dataLen!!
    }

    /**
     * 从当前位置写入打包字节流
     */
    override fun fillBuffer(buf: ByteBuf) {
        computeDataLen()

        buf.writeBytes(buf.alloc().buffer().apply {
            writeByte(count!!.toInt())

            writeByte(flag!!.back)

            for (idx in 0..(count!! - 1)) {
                writeBytes(forwardStrList!![idx].hexArray)

                if (1 == flag?.dayBillContent) {
                    writeBytes(reverseStrList!![idx].hexArray)
                }
            }
        }
        )
    }

    /**
     * 解析字节流，从buf当前位置开始，并且消费其中的字节。
     */
    override fun <T : SanchuanData> parseBuffer(buf: ByteBuf): T? {
        buf.duplicate().apply {
            count = readByte().toShort().and(0xFF)
            flag = DayBillFlagType(readByte().toInt())
        }
        computeDataLen()

        buf.readBytes(dataLen!!).apply {
            skipBytes(2)

            forwardStrList = ArrayList()
            if (flag?.dayBillContent == 1) {
                reverseStrList = ArrayList()
            }

            for (idx in 0..(count!! - 1)) {
                forwardStrList?.add(
                        if (flag?.dayBillFormat == 0) BcdString.create(this, 5)
                        else BcdString.create(this, 3))

                if (flag?.dayBillContent == 1) {
                    reverseStrList?.add(
                            if (flag?.dayBillFormat == 0) BcdString.create(this, 5)
                            else BcdString.create(this, 3)
                    )
                }
            }
        }

        return this as T
    }

}

/**
 * 1 日结数据指示
 */
class DayBillFlagType(v1: Int) : Bit32Array(v1) {
    /**
     * BIT0~1 日结累计流量格式
     * 0 格式 0 格式见参数表，参数编码 1110
    1 格式 1 累计流量 3 字节，单位 0.1 立方米。 16 进制低字节在前
    2 保留
    3 保留
     */
    var dayBillFormat: Int = 0
        get() {
            field = get(0, 1)
            return field
        }
        set(value) {
            field = value
            set(0, 1, field)
        }

    /**
     * BIT2~3 日结数据内容
    0 内容 0 日结累计流量
    1 内容 1 日结累计正流+日结累计逆流
    2 保留
    3 保留
     */
    var dayBillContent: Int = 0
        get() {
            field = get(2, 3)
            return field
        }
        set(value) {
            field = value
            set(2, 3, field)
        }

}
